function modList(mods) {
	var me = this;
	var savedmods = '';
	if ( mods.length > 0 ) {
		this.mods = mods;
	}
	else {
		this.mods = Array();
	}
	
	// PUBLIC METHODS
	// Filter mods using a large array
	this.filter = function(filterArray) {
		var returnMods = me.mods;
		
		var nextMods = Array();
		var num = 0;
		if ( filterArray.installed != undefined ) {
			for ( x in returnMods ) {
				if ( returnMods[x].installed == filterArray.installed ) {
					nextMods[num] = returnMods[x];
					num++;
				}
			}
			returnMods = nextMods;
		}
		
		var nextMods = Array();
		var num = 0;
		if ( filterArray.latest != undefined ) {
			for ( x in returnMods ) {
				if ( returnMods[x].latest == filterArray.latest ) {
					nextMods[num] = returnMods[x];
					num++;
				}
			}
			returnMods = nextMods;
		}
		
		return new modList(returnMods);
	}
	
	this.sort = function(sortValue) {
		var newMods = me.mods;
		var num = 0;
		
		switch (sortValue) {
			case 'name':
				function sortByName(a, b) {
					var x = a.creation.json.name.toLowerCase();
					var y = b.creation.json.name.toLowerCase();
					return ((x < y) ? -1 : ((x > y) ? 1 : 0));
				}
				
				newMods.sort(sortByName);
			break;
			case 'author':
				function sortByAuthor(a, b) {
					var x = a.creation.json.team[0].name.toLowerCase();
					var y = b.creation.json.team[0].name.toLowerCase();
					return ((x < y) ? -1 : ((x > y) ? 1 : 0));
				}
				
				newMods.sort(sortByAuthor);
			break;
			case 'releasedate':
				function sortByReleaseDate(a, b) {
					var x = a.json.date.toLowerCase();
					var y = b.json.date.toLowerCase();
					return ((x < y) ? -1 : ((x > y) ? 1 : 0));
				}
				
				newMods.sort(sortByReleaseDate);
			break;
		}
		
		return new modList(newMods);
	}
	
	this.group = function(groupValue) {
		var num = 0;
		var seen = Array();
		var nameDetails = Array();
		var newMods = Array();
		
		switch (groupValue) {
			case 'tag':
				for ( x=0; x < me.mods.length; x++ ) {
					for ( y=0; y < me.mods[x].creation.json.tags.length; y++ ) {
						if ( seen.inArray(me.mods[x].creation.json.tags[y].name) ) {
							newMods[me.mods[x].creation.json.tags[y].id].push(me.mods[x]);
						}
						else {
							seen[num] = me.mods[x].creation.json.tags[y].name;
							num++;
							
							newMods[me.mods[x].creation.json.tags[y].id] = Array();
							newMods[me.mods[x].creation.json.tags[y].id].push(me.mods[x]);
							
							nameDetails[me.mods[x].creation.json.tags[y].id] = me.mods[x].creation.json.tags[y].name;
						}
					}
				}
			break;
			case 'type':
				for ( x=0; x < me.mods.length; x++ ) {
					if ( seen.inArray(me.mods[x].json.type) ) {
						newMods[me.mods[x].json.type].push(me.mods[x]);
					}
					else {
						seen[num] = me.mods[x].json.type;
						num++;
						
						newMods[me.mods[x].json.type] = Array();
						newMods[me.mods[x].json.type].push(me.mods[x]);
						
						nameDetails[me.mods[x].json.type] = me.mods[x].json.type;
					}
				}
			break;
		}
		
		var returnMods = Array();
		
		for ( x in newMods ) {
			if ( typeof(newMods[x]) == 'object' ) {
					var returnList = new modList(newMods[x]);
					var returnArray = Array();
					returnArray.name = nameDetails[x];
					returnArray.mods = returnList;
					returnMods.push(returnArray);
			}
		}
		
		function sortByName(a, b) {
			var x = a.name.toLowerCase();
			var y = b.name.toLowerCase();
			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
		}
		returnMods.sort(sortByName);
		
		return returnMods;
	}
	
	// Get a new list of mods from the server
	this.getModList = function() {
		me.mods = Array();
		if ( savedmods == '' ) {
			$.getJSON('http://95.172.11.34/overgrowth/getCreations.php', function(data){
				savedmods = data;
				populateMods(data);
				checkInstalled();
			});
		}
		else {
			populateMods(savedmods);
			checkInstalled();
		}
	}
	
	// Rescan the folders for installed mods
	this.refreshInstalled = function() {
		me.getModList();
	}
	
	// Debug functions
	this.outputMods = function(){
		for ( x in me.mods ) {
			alert(me.mods[x].creation.json.name);
		}
	}
	this.outputInstalled = function(){
		var installed = this.filter({
			installed: true
		});
		for ( x in installed.mods ) {
			alert(installed.mods[x].creation.json.name);
		}
	}
	this.outputOutofdate = function(){
		var outofdate = this.filter({
			latest: false
		});
		for ( x in outofdate.mods ) {
			alert(outofdate.mods[x].creation.json.name);
		}
	}
	
	// PRIVATE METHODS
	// Put returned mods into the mods array
	function populateMods(data) {
		for ( x in data.creations ) {
			var creation = new modCreation(data.creations[x]);
			for ( y in data.creations[x].versions ) {
				var version = new modVersion(data.creations[x].versions[y], creation);
				creation.versions[creation.versions.length] = version;
				me.mods[me.mods.length] = version;
			}
		}
	}
	// Check which mods are installed
	function checkInstalled() {
		// TODO: Get rid of this massive ugly loop 'cause it's massive and ugly
		var directory1Str = 'file:///' + dir.nativePath + '/Custom/';
		var directory1 = new air.File(directory1Str);
		if ( directory1.exists == true ) {
			var contents1 = directory1.getDirectoryListing();
			for (i1 = 0; i1 < contents1.length; i1++) { 
				if ( contents1[i1].isDirectory == true ) {
					var directory2Str = 'file:///' + dir.nativePath + '/Custom/' + contents1[i1].name + '/';
					var directory2 = new air.File(directory2Str);
					var contents2 = directory2.getDirectoryListing();
					for (i2 = 0; i2 < contents2.length; i2++) { 
						if ( contents2[i2].isDirectory == true ) {
							var directory3Str = 'file:///' + dir.nativePath + '/Custom/' + contents1[i1].name + '/' + contents2[i2].name + '/';
							var directory3 = new air.File(directory3Str);
							var contents3 = directory3.getDirectoryListing();
							for (i3 = 0; i3 < contents3.length; i3++) { 
								if ( contents3[i3].isDirectory == true ) {
									var directory4Str = 'file:///' + dir.nativePath + '/Custom/' + contents1[i1].name + '/' + contents2[i2].name + '/' + contents3[i3].name + '/';
									var directory4 = new air.File(directory4Str);
									var contents4 = directory4.getDirectoryListing();
									for (i4 = 0; i4 < contents4.length; i4++) { 
										if ( contents4[i4].isDirectory == true ) {
											// Can go no further :( (unless I write some unneeded code :P)
										}
										else if ( contents4[i4].name.toLowerCase() == "about.json" ) {
											// FOUND ONE!
											processAboutJson(contents4[i4]);
										}
									}
								}
								else if ( contents3[i3].name.toLowerCase() == "about.json" ) {
									// FOUND ONE!
									processAboutJson(contents3[i3]);
								}
							}
						}
					}
				}
			}
		}
		afterLoad();
	}
	// Find out the installed mods place int he mods array and set its installed property to true
	function processAboutJson(about_json) {
		jsonfile = about_json;
		var fileStream = new air.FileStream(); 
		fileStream.open(jsonfile, air.FileMode.READ); 
		var contents = fileStream.readUTFBytes(fileStream.bytesAvailable);
		fileStream.close();
		// TODO: Get rid of eval and put in a proper JSON praser for security
		var json = eval('(' + contents + ')');
		
		for ( x=0; x<me.mods.length; x++ ) {
			if ( me.mods[x].creation.json.name == json['Project']['Content']['name'] && me.mods[x].json.version == json['Project']['Content']['version'] ) {
				me.mods[x].installed = true;
				me.mods[x].creation.installed = true;
			}
		}
	}
}

function modVersion(json, creation) {
	var me = this;
	this.creation = creation;
	this.json = json;
	this.installed = false;
	this.latest = false;
	
	if ( this.creation.json.versions[0].version <= this.json.version ) {
		this.latest = true;
	}
	
	this.install = function(silent, finishFunction) {
		function nextFile() {
			function completeHandler(event) {
				var loader = air.URLLoader(event.target);
				var data = loader.data;
				var urlStr = 'file:///' + dir.nativePath + '/Custom/' + files[i].local + '/' + files[i].filename;
				var savefile = new air.File(urlStr);
				var stream = new air.FileStream();
				stream.open(savefile, air.FileMode.WRITE);
				stream.writeUTFBytes(data);
				stream.close();
				
				air.trace('File Saved - ' + files[i].local + '/' + files[i].filename);
				overallprogress = ((i+1)/total)*100;
				air.trace('Overall: ' + overallprogress);
				
				if ( silent != true ) {
					$('#overall-progress').progressbar('option', 'value', overallprogress);
				}
				
				if ( overallprogress == 100 ) {
					master.refreshInstalled();
					
					if ( silent != true ) {
						dialog.dialog('option', 'buttons', {
							"Done": function() {
								$(this).dialog('close').remove();
							}
						});
					}
					else {
						finishFunction;
					}
				}
				else {
					i++;
					
					if ( silent != true ) {
						fileprogresstext.html('Done');
						$('#file-progress').progressbar('option', 'value', 0);
					}
					nextFile();
				}
			}
			
			function progressHandler(event) {
				fileprogress = (event.bytesLoaded/event.bytesTotal)*100;
				
				if ( silent != true ) {
					fileprogresstext.html(Math.round(fileprogress) + '%');
					$('#file-progress').progressbar('option', 'value', fileprogress);
				}
			}
			
			var loader = new air.URLLoader();
			loader.addEventListener(air.Event.COMPLETE, completeHandler);
			loader.addEventListener(air.ProgressEvent.PROGRESS, progressHandler);
			air.trace(files[i].remote);
			var li = $('<li></li>').html('Downloading: <em>' + files[i].local + '/' + files[i].filename + '</em>... ').prependTo(downloadlist);
			var fileprogresstext = $('<span></span>').html('0%').appendTo(li);
			var request = new air.URLRequest(files[i].remote);
			try {
				loader.load(request);
			}
			catch (error) {
				air.trace("Unable to load requested document.");
			}
		}
		
		var i = 0;
		var files = me.json.files;
		var total = files.length;
		
		if ( silent != true ) {
			var dialog = $('<div id="progress-window"></div>').appendTo('body');
			dialog.dialog({
				modal: true,
				height: 275,
				width: 500,
				title: "Downloading...",
				draggable: false,
				resizable: false,
				closeOnEscape: false
			});
			$('<h1>Overall</h1>').appendTo(dialog);
			$('<div id="overall-progress"></div>').progressbar({value:0}).appendTo(dialog);
			$('<h1>Current File</h1>').appendTo(dialog);
			$('<div id="file-progress"></div>').progressbar({value:0}).appendTo(dialog);
			var downloadlist = $('<ul id="download-list"></ul>').appendTo(dialog);
		}
		
		nextFile();
	}
	
	this.uninstall = function(silent, finishFunction) {
		if ( silent != true ) {
			var dialog = $('<div id="uninstall-window"></div>').appendTo('body');
			dialog.dialog({
				modal: true,
				height: 0,
				width: 500,
				title: "Are you sure you want to uninstall?",
				draggable: false,
				resizable: false,
				closeOnEscape: false,
				buttons: {
					"No": function() {
						closeDialog();
					},
					"Yes": function() {
						doUninstall();
					}
				}
			});
		}
		else {
			doUninstall();
		}
		
		function doUninstall() {
			var i = 0;
			var files = me.json.files;
			var urlStr = 'file:///' + dir.nativePath + '/Custom/' + files[i].local + '/' + files[i].filename;
			var file = new air.File(urlStr);
			file = file.parent;
			file.deleteDirectory(true);
			file = file.parent;
			if ( file.getDirectoryListing().length == 0 ) {
				file.deleteDirectory();
			}
			master.refreshInstalled();
			if ( silent != true ) {
				closeDialog();
			}
			else {
				finishFunction();
			}
		}
		function closeDialog() {
			dialog.dialog('close').remove();
		}
	}
}

function modCreation(json) {
	var me = this;
	this.json = json;
	this.versions = Array();
	this.installed = false;
	
	this.getLatest = function() {
		var most = me.versions[0];
		for ( x in me.versions ) {
			if ( most.json.version < me.versions[x].json.version ) {
				most = me.version[x];
			}
		}
		
		return most;
	}
	
	this.getInstalled = function() {
		var install = me.versions[0];
		for ( x in me.versions ) {
			if ( me.versions[x].installed == true ) {
				install = me.versions[x];
			}
		}
		
		return install;
	}
}